var GridSelector = '.gridcontrol';
var GridControl = Class.create(FormControl, {
    selector:GridSelector,
    newIndex:null,
    rowSelector:null,
    cellSelector:null,
    filterSelector:null,
    actionSelector:null,
    actionRowSelector: null,
    editboxSelector:null,
    fieldSelect:null,

    initialize: function($super, element)
    {
        this.newIndex = 0;
        this.rowSelector = '.row';
        this.cellSelector = '.cell';
        this.filterSelector = '.filter';
        this.actionSelector = '.action_item';
        this.actionRowSelector = this.rowSelector +' '+ this.actionSelector;
        this.editboxSelector = '.editbox';
        $super(element);
        this.fieldSelect = this.view.getAttribute('fieldselect');
    },

    getDefaultOptions: function()
    {
        return {
            submitOnEnter: true,
            checkForChanges: true
        };
    },

    setFilter: function(key, value)
    {
        var filter = this.findOne('input[name="filter['+key+']"]');
        if (filter)
            this.setValue(filter, value);
        else
            this.setParam('filter['+key+']', value);
    },

    removeFilter: function(key)
    {
        var e = this.findOne('input[name="filter['+key+']"]');
        if (e) e.remove();
    },

    observeEvent: function($super)
    {
        $super();
        this.observeRows();
        this.observeBasicActions();
        this.observeFilter();
        this.observeSelectActions();
        this.observeMassActions();
        this.observeColumnResize();
    },

    getSelectedRowIds: function()
    {
        var me = this;
        var ids = new Array();
        this.findRow('.selected').each(function(e){
            ids.push(me.getRecordId(e));
        });
        return ids;
    },

    getSelectedRows: function()
    {
        return this.findRow('.selected');
    },

    getRecordId: function(row)
    {
        return row.getAttribute('key');
    },

    findRow: function(selector)
    {
        selector = Object.isUndefined(selector) ? '' : selector;
        return this.find(this.rowSelector + selector);
    },

    findCell: function(selector)
    {
        selector = Object.isUndefined(selector) ? '' : selector;
        return this.find(this.cellSelector + selector);
    },

    findFilter: function(selector)
    {
        selector = Object.isUndefined(selector) ? '' : selector;
        return this.find(this.filterSelector + selector);
    },

    observeRows: function()
    {
        var me = this;
        this.findRow(':nth-child(2n)').invoke('addClassName', 'alternate');
        this.findRow().invoke('observe', 'click', function(event){
            me.toggleRowSelect(this, event);
        });
        this.findRow(' input.check[type="checkbox"]').invoke('observe', 'click', function(event){
            me.checkboxClick(this, event);
        });
        this.findRow(' .thumbimg').each(function(e){
            var cell = e.up(me.cellSelector);
            var src = cell.down('img').src;
            new Tooltip(cell, '<img class="tooltip_img" src="'+src+'" />');
        });

        this.find(this.actionRowSelector+'.delete').invoke('observe', 'click', function(event){
            me.deleteItem(this, event);
        });
        this.find(this.actionRowSelector+'.inline_edit').each(function(e){
            e.control = me;
            e.toggleRowEdit = me.toggleRowEdit;
            e.observe('click', me.toggleRowEdit);
        });
        this.find(this.actionRowSelector+'.process').invoke('observe', 'click', function(event){
            me.selectNone();
            var row = this.up(me.rowSelector);
            row.addClassName('editing');
            me.selectRow(row, true);
            event.stopPropagation();

            var action = this.getAttribute('action');
            var confirm = !this.hasClassName('noconfirm');
            me.processSelecteds(action, confirm, false, false, this.action);
        });

        this.findCell().each(function(e){
            e.find('.box').invoke('observe', 'change', me.inputChanged);
            e.observe('click', function(event){
                if (event.altKey){
                    this.toggleClassName('selected');
                    event.stopPropagation();
                }
            });
            e.observe('dblclick', function(event){
                me.toggleCellEdit(this);
                event.stopPropagation();
            });
            if (e.hasClassName('oneclickedit'))
            {
                e.observe('click', function(event){
                    if (!this.hasClassName('editing')) me.enableCellEdit(e);
                    event.stopPropagation();
                });
            }
        });

        this.observeActionBox();
    },

    observeBasicActions: function()
    {
        var me = this;
        this.view.control = this;
        this.find('input.check_all').invoke('observe', 'click', function(){
            me.setAllCheckbox(this.checked);
        });
        this.find('.pager select').invoke('observe', 'change', this.refresh.bind(this));
        this.find('.sortable').invoke('observe', 'click', function(){
            me.sortColumn(this);
        });
        this.find('.prevPage').invoke('observe', 'click', function(){
           me.prevPage();
        });
        this.find('.nextPage').invoke('observe', 'click', function(){
           me.nextPage();
        });
    },

    gotoPage: function(page)
    {
        this.find('select.page').each(function(e){
            e.value = page;
        });
        this.refresh();
    },

    nextPage: function()
    {
        this.find('select.page').each(function(e){
            e.value++;
        });
        this.refresh();
    },

    prevPage: function()
    {
        this.find('select.page').each(function(e){
            e.value--;
        });
        this.refresh();
    },

    observeFilter: function()
    {
        var me = this;
        this.findFilter(' .box').each(function(e){
            e.originValue = e.value;
            e.observe('change', me.inputChanged);
            if (e.value) e.addClassName('filtered');
        });

        this.findFilter(' select').invoke('observe', 'change', this.refresh.bind(this));
        this.find('.clear_filter').invoke('observe', 'click', this.clearFilter.bind(this));
        this.findFilter(' input.daterange_picker').each(function(e){
            var dr = new DaterangeControl(e);
            dr.applyCallback = function(){
                me.refresh();
            };
        });

        this.findFilter(' '+GridSelectSelector).each(function(e){
            new GridSelectControl(e);
            e.control.observe('rowselect', me.refresh.bind(me));
        });
    },

    observeActionBox: function()
    {
        this.findRow(' .actionbox').each(function(e){
            if (e.down('.action_wrapper'))
            {
                e.observe('mouseover', function(){
                    this.down('div.action_wrapper').show();
                });
                e.observe('mouseout', function(){
                    this.down('div.action_wrapper').hide();
                });
            }
        });
    },

    observeColumnResize: function()
    {
        this.find('thead .caption th').each(function(e){
			new ResizerW(e);
            e.setStyle({width:e.getStyle('width')});
        });
        updateAllResizers();
    },

    observeSelectActions: function()
    {
        this.find('.select_all').invoke('observe', 'click', this.selectAll.bind(this));
        this.find('.select_none').invoke('observe', 'click', this.selectNone.bind(this));
        this.find('.select_editing').invoke('observe', 'click', this.selectEditing.bind(this));
        this.find('.select_inverse').invoke('observe', 'click', this.selectInverse.bind(this));
    },

    observeMassActions: function()
    {
        var me = this;
        this.find('.add_new').invoke('observe', 'click', this.addNew.bind(this));
        this.find('.toogle_edit').invoke('observe', 'click', this.editSelected.bind(this));
        this.find('.mass_action').invoke('observe', 'click', function(){
            var action = this.getAttribute('action');
            var confirm = !this.hasClassName('noconfirm');
            var selected_check = !this.hasClassName('noselected');
            var file_export = this.hasClassName('file_export');
            me.processSelecteds(action, confirm, selected_check, file_export, this.innerHTML);
        });
    },

    beforeSubmit: function()
    {
        if (typeof(tinyMCE)!='undefined')
        {
            tinyMCE.triggerSave();
            this.find('.htmleditor').each(function(e){
                tinyMCE.execCommand('mceRemoveControl', false, e);
            });
        }
        this.removeUnchangedFilter();
        this.find(this.editboxSelector).invoke('remove');
    },

    removeUnchangedInputs: function()
    {
        var me = this;
        this.findRow('.editing .inline_edit').each(function(e){
            if (!e.up(me.rowSelector).down('.changed') && e.toggleRowEdit)
                e.toggleRowEdit();
        });
        this.findCell('.editing input:not(.changed)').each(function(e){me.undoEdit(e);});
        this.findCell('.editing select:not(.changed)').each(function(e){me.undoEdit(e);});
        this.findCell('.editing input[type=checkbox].changed').each(function(e){me.undoCheckboxEdit(e);});
    },

    removeUnchangedFilter: function()
    {
        this.findFilter(' .box').each(function(e){ if(e.value=='') e.disable();});
    },

    undoCheckboxEdit: function(checkbox)
    {
        var cell = checkbox.up(this.cellSelector);
        checkbox.hide().checked = true;
        cell.insert(checkbox.value);
    },

    undoEdit: function(input)
    {
        this.cancelCellEdit(input.up(this.cellSelector));
    },

    checkForChanges: function()
    {
        var me = this;
        this.findCell('.editing input:not(.changed)').each(function(e){
            if (e.value != e.up(me.cellSelector).getAttribute('value')) e.addClassName('changed');
        });
        this.removeUnchangedInputs();
        var changes = this.findCell('.editing .box.changed').length;
        return changes>0;
    },

    checkForFilterChanges: function()
    {
        this.findFilter('.editing .box').each(function(e){
            if (e.value != e.originValue) e.addClassName('changed');
            else e.removeClassName('changed');
        });
        var changes = this.findFilter('.editing input.changed').length;

        return changes>0;
    },

    editSelected: function()
    {
        this.findRow('.selected .inline_edit').invoke('toggleRowEdit');
        //this.findCell('.selected.editable').each(this.toggleCellEdit);
    },

    toggleCellEdit: function(e)
    {
        if (!e.hasClassName('editable')) return;
        var editing = e.hasClassName('editing');
        if (!editing) this.enableCellEdit(e);
        else this.cancelCellEdit(e);
        updateAllResizers();
    },

    toggleRowEdit: function(event)
    {
        var control = this.control;
        var row = this.up(control.rowSelector);
        var cells = row.find(control.cellSelector+'.editable');
        var editing = row.hasClassName('editing');
        if (!editing)
        {
            cells.each(function(e){control.enableCellEdit(e);});
            row.addClassName('editing');
            if (this.hasClassName('cbutton')) this.addClassName('orange').value = 'Cancel';
            else this.update('Cancel');
        }
        else
        {
            cells.each(control.cancelCellEdit);
            row.removeClassName('editing');
            if (this.hasClassName('cbutton')) this.removeClassName('orange').value = 'Edit';
            else this.update('Edit');
        }
        if (event) event.stopPropagation();
        updateAllResizers();
    },

    enableCellEdit: function(cell)
    {
        if (cell.hasClassName('editing')) return;
        this.saveCellFormatedValue(cell);
        var cell_value = cell.hasClassName('notformated') ? cell.formated : cell.getAttribute('value');
        var editbox = this.getEditbox(cell, cell_value);

        var box = cell.addClassName('editing').update(editbox).down('.box').observe('change', this.inputChanged);

        if (box.type!='checkbox')
        {
            box.value = box.originValue = cell_value;
            if (box.getAttribute('type')=='datetime')
            {
                this.initDatepicker(box);
            }
            else if (box.hasClassName('gridselect_ready'))
            {
                box.addClassName('gridselect');
                new GridSelectControl(box);
            }
            else if (box.hasClassName('htmleditor'))
            {
                box.addClassName('changed');
                tinyMCE.execCommand('mceAddControl', false, box);
            }
        }

        this.fire('celledit', {cell: cell});
    },

    getEditbox: function(cell, cell_value)
    {
        var editbox_template = this.findOne(this.editboxSelector+' .edit-'+cell.getAttribute('field'));
        var id = this.getRecordId(cell.up(this.rowSelector));

        var editbox = editbox_template.innerHTML.gsub(/#id/, id).gsub(/#v/, cell_value);
        var display = cell.down('.displayvalue');
        display = display ? display.innerHTML : '';
        editbox = editbox.gsub(/#f/, display);

        var checked = cell_value>0 ? 'checked="checked"' : '';
        return editbox.gsub(/#checked/, checked);
    },

    saveCellFormatedValue: function(e)
    {
        if (!e.formated){
            e.formated = e.innerHTML;
        }
    },

    initDatepicker: function(e)
    {
        e.observe('click', function(){
            new CalendarDateSelect(this);
        }).observe('blur', this.inputChanged);
    },

    cancelCellEdit: function(cell)
    {
        var box = cell.down('.box');
        if (box && box.hasClassName('htmleditor')) tinyMCE.execCommand('mceRemoveControl', false, box);
        cell.removeClassName('editing').update(cell.formated);
    },

    inputChanged: function()
    {
        if (this.type=='checkbox') this.value = this.checked ? 1:0;

        if (this.value != this.originValue)
            this.addClassName('changed');
        else
            this.removeClassName('changed');
    },

    clearFilter: function()
    {
        var me = this;
        this.find('.filterrow .filter input', '.filterrow .filter select').each(function(e){
            me.setValue(e, '');
        });
        this.refresh();
    },

    sortColumn: function(e)
    {
        var sort_order = this.findOne('.sort_order');
        var sort_field = this.findOne('.sort_field');

        if (e.hasClassName('asc')) this.setValue(sort_order, 'desc');
        else if(e.hasClassName('desc')) this.setValue(sort_order, '');
        else this.setValue(sort_order, 'asc');
        this.setValue(sort_field, sort_order.value? e.title:null);
        this.refresh();
    },

    discardAllChanges: function()
    {
        var me = this;
        this.findRow('.editing .inline_edit').each(function(e){
            if (e.toggleRowEdit) e.toggleRowEdit();
        });
        this.findCell('.editing').each(function(e){
            me.cancelCellEdit(e);
        });
    },

    processSelecteds: function(action, confirmRequired, selected_check, file_export, label)
    {
        if (!label) label = action;
        if (selected_check && this.getSelectedRows().length < 1) {alert('No selected record');return;}
        if (confirmRequired && !confirm('Do you want to `'+label+'` selected items?')) return;
        this.setAction(action);

        if (file_export)
            this.submitNormal();
        else
            this.refresh();
    },

    deleteItem: function(e, event)
    {
        this.selectNone();
        var row = e.up(this.rowSelector);
        row.addClassName('editing');
        this.selectRow(row, true);
        if (!this.processDelete()) row.removeClassName('editing');
        if (event) event.stopPropagation();
    },

    processDelete: function()
    {
        if (confirm('Do you want to delete this record?'))
        {
            this.processAction('Delete');
            return true;
        }
        else return false;
    },

    checkboxClick: function(e, event)
    {
        var row = e.up(this.rowSelector);
        if(e.checked)
            row.addClassName('selected');
        else
            row.removeClassName('selected');
        event.stopPropagation();
    },

    toggleRowSelect: function(e, event)
    {
        var element = event.element();
        if (element.tagName != 'INPUT'
            && element.tagName != 'SELECT'
            && !element.hasClassName('node_icon')
            && !element.hasClassName('action_item'))
        {
            var c = e.down('input.check[type="checkbox"]');
            if (c) this.selectRow(e, !c.checked, c);
        }

        var id = this.getRecordId(e);
        var display = this.fieldSelect ? this.getFieldValue(e, this.fieldSelect) : id;
        var memo = {id:id, display:display};
        this.fire('rowselect', memo);
        if (this.onRowSelect) this.onRowSelect(memo); // hack for grid select
    },

    getFieldValue: function(row, fieldname)
    {
        return row.down('.cell[field='+fieldname+']').getAttribute('value');
    },

    setAllCheckbox: function(checked)
    {
        var me = this;
        this.findRow().each(function(row){
            me.selectRow(row, checked);
        });
    },

    selectRow: function(row, checked, e)
    {
        if (!e) e = row.down('input[type="checkbox"]');
        e.checked = checked;
        if(e.checked)
            row.addClassName('selected');
        else
            row.removeClassName('selected');
    },

    selectAll: function()
    {
        this.findOne('input.check_all').checked = true;
        this.setAllCheckbox(true);
    },

    selectNone: function()
    {
        this.find('input.check_all[type="checkbox"]').first().checked = false;
        this.setAllCheckbox(false);
        this.findCell('.selected').each(function(e){e.removeClassName('selected');});
    },

    selectEditing: function()
    {
        var me = this;
        this.findRow().each(function(row){me.selectRow(row, false);});
        this.findRow('.editing').each(function(row){me.selectRow(row, true);});
        this.findRow(':not(.selected) '+this.cellSelector+'.editing').each(function(e){e.toggleClassName('selected');});
    },

    selectInverse: function()
    {
        var me = this;
        var selected = this.getSelectedRows();
        this.findRow(':not(.selected)').each(function(row){me.selectRow(row, true);});
        selected.each(function(row){me.selectRow(row, false);});
    },

    addNew: function()
    {
        var me = this;
        var new_id = "new_" + this.newIndex++;
        this.findOne('.data tbody').insert('<tr class="row addnew editing '+new_id+'" key="'+new_id+'"></tr>');
        var editbox = this.findOne(this.editboxSelector);

        var row = this.findOne('.'+new_id);
        row.update(editbox.innerHTML);

        row.find(this.cellSelector+'.editable').each(function(e)
        {
            e.update('');
            me.enableCellEdit(e);
            var box = e.down('.box');
            var filter = me.findOne(me.filterSelector+'.field-'+e.getAttribute('field')+' select');
            if (filter && filter.value) box.value = filter.value;

            if (box.value && box.value != '#NULL') box.addClassName('changed');

            filter = me.findOne(me.filterSelector+'.field-'+e.getAttribute('field')+' '+GridSelectSelector);
            if (filter)
            {
                box = e.down(GridSelectSelector);
                if (box && (filter.value != ''))
                {
                    box.control.setValue(filter.value);
                    box.control.setDisplayValue(filter.getAttribute('display'));
                }
            }
        });

        var cancel = row.down('.inline_edit');
        cancel.toggleRowEdit = function(){this.up(me.rowSelector+'.editing').remove()};
        cancel.observe('click', function(){this.toggleRowEdit()});
    }
});
